package com.automotive.can1939.model;

import java.util.Arrays;

/**
 * J1939协议帧数据模型
 * 基于SAE J1939标准的CAN总线协议
 */
public class J1939Frame {
    // J1939 29位扩展CAN ID结构
    private int priority;        // 优先级 (3位)
    private int reservedBit;     // 保留位 (1位)
    private int dataPage;        // 数据页 (1位)
    private int pduFormat;       // PDU格式 (8位)
    private int pduSpecific;     // PDU特定 (8位)
    private int sourceAddress;   // 源地址 (8位)
    
    // 完整的29位CAN ID
    private int canId;
    
    // 数据部分
    private byte[] data;         // 数据字节 (最多8字节)
    private int dataLength;      // 数据长度
    private long timestamp;      // 时间戳
    
    // J1939特有字段
    private int pgn;            // 参数组号 (Parameter Group Number)
    private String pgnName;
    private String spnName;     // 可疑参数号名称
    
    public J1939Frame() {
        this.data = new byte[8];
        this.timestamp = System.currentTimeMillis();
    }
    
    /**
     * 从29位CAN ID构造J1939帧
     */
    public J1939Frame(int canId, byte[] data) {
        this.canId = canId;
        this.data = Arrays.copyOf(data, Math.min(data.length, 8));
        this.dataLength = this.data.length;
        this.timestamp = System.currentTimeMillis();
        
        // 解析29位CAN ID
        parseCanId(canId);
    }
    
    /**
     * 使用J1939字段构造帧
     */
    public J1939Frame(int priority, int dataPage, int pduFormat, int pduSpecific, 
                      int sourceAddress, byte[] data) {
        this.priority = priority & 0x07;
        this.dataPage = dataPage & 0x01;
        this.pduFormat = pduFormat & 0xFF;
        this.pduSpecific = pduSpecific & 0xFF;
        this.sourceAddress = sourceAddress & 0xFF;
        this.reservedBit = 0;
        
        this.data = Arrays.copyOf(data, Math.min(data.length, 8));
        this.dataLength = this.data.length;
        this.timestamp = System.currentTimeMillis();
        
        // 构建29位CAN ID
        buildCanId();
        
        // 计算PGN
        calculatePgn();
    }
    
    /**
     * 解析29位CAN ID为J1939字段
     */
    private void parseCanId(int canId) {
        this.priority = (canId >> 26) & 0x07;
        this.reservedBit = (canId >> 25) & 0x01;
        this.dataPage = (canId >> 24) & 0x01;
        this.pduFormat = (canId >> 16) & 0xFF;
        this.pduSpecific = (canId >> 8) & 0xFF;
        this.sourceAddress = canId & 0xFF;
        
        calculatePgn();
    }
    
    /**
     * 从J1939字段构建29位CAN ID
     */
    private void buildCanId() {
        this.canId = (priority << 26) | (reservedBit << 25) | (dataPage << 24) |
                     (pduFormat << 16) | (pduSpecific << 8) | sourceAddress;
    }
    
    /**
     * 计算PGN (参数组号)
     */
    private void calculatePgn() {
        if (pduFormat < 240) {
            // PDU1格式: PGN = 数据页 + PDU格式 + 0x00
            this.pgn = (dataPage << 16) | (pduFormat << 8);
        } else {
            // PDU2格式: PGN = 数据页 + PDU格式 + PDU特定
            this.pgn = (dataPage << 16) | (pduFormat << 8) | pduSpecific;
        }
    }
    
    /**
     * 判断是否为PDU1格式 (点对点通信)
     */
    public boolean isPdu1Format() {
        return pduFormat < 240;
    }
    
    /**
     * 判断是否为PDU2格式 (广播通信)
     */
    public boolean isPdu2Format() {
        return pduFormat >= 240;
    }
    
    /**
     * 获取目标地址 (仅PDU1格式有效)
     */
    public int getDestinationAddress() {
        return isPdu1Format() ? pduSpecific : 0xFF; // 0xFF表示全局地址
    }
    
    /**
     * 获取组扩展 (仅PDU2格式有效)
     */
    public int getGroupExtension() {
        return isPdu2Format() ? pduSpecific : 0;
    }
    
    // Getters and Setters
    public int getPriority() {
        return priority;
    }
    
    public void setPriority(int priority) {
        this.priority = priority & 0x07;
        buildCanId();
    }
    
    public int getDataPage() {
        return dataPage;
    }
    
    public void setDataPage(int dataPage) {
        this.dataPage = dataPage & 0x01;
        buildCanId();
        calculatePgn();
    }
    
    public int getPduFormat() {
        return pduFormat;
    }
    
    public void setPduFormat(int pduFormat) {
        this.pduFormat = pduFormat & 0xFF;
        buildCanId();
        calculatePgn();
    }
    
    public int getPduSpecific() {
        return pduSpecific;
    }
    
    public void setPduSpecific(int pduSpecific) {
        this.pduSpecific = pduSpecific & 0xFF;
        buildCanId();
        calculatePgn();
    }
    
    public int getSourceAddress() {
        return sourceAddress;
    }
    
    public void setSourceAddress(int sourceAddress) {
        this.sourceAddress = sourceAddress & 0xFF;
        buildCanId();
    }
    
    public int getCanId() {
        return canId;
    }
    
    public int getPgn() {
        return pgn;
    }

    public void setPgn(int pgn) {
        this.pgn = pgn;
    }

    public String getPgnName() {
        return pgnName;
    }

    public void setPgnName(String pgnName) {
        this.pgnName = pgnName;
    }

    public byte[] getData() {
        return data;
    }
    
    public void setData(byte[] data) {
        this.data = Arrays.copyOf(data, Math.min(data.length, 8));
        this.dataLength = this.data.length;
    }
    
    public int getDataLength() {
        return dataLength;
    }
    
    public long getTimestamp() {
        return timestamp;
    }
    
    public void setTimestamp(long timestamp) {
        this.timestamp = timestamp;
    }
    
    public String getSpnName() {
        return spnName;
    }
    
    public void setSpnName(String spnName) {
        this.spnName = spnName;
    }
    
    /**
     * 获取数据的十六进制字符串表示
     */
    public String getDataHexString() {
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < dataLength; i++) {
            sb.append(String.format("%02X ", data[i] & 0xFF));
        }
        return sb.toString().trim();
    }
    
    /**
     * 从十六进制字符串设置数据
     */
    public void setDataFromHexString(String hexString) {
        String[] hexBytes = hexString.trim().split("\\s+");
        byte[] newData = new byte[Math.min(hexBytes.length, 8)];
        
        for (int i = 0; i < newData.length; i++) {
            newData[i] = (byte) Integer.parseInt(hexBytes[i], 16);
        }
        
        setData(newData);
    }
    
    /**
     * 获取PGN的十六进制字符串
     */
    public String getPgnHexString() {
        return String.format("0x%05X", pgn);
    }
    
    /**
     * 获取完整的CAN ID十六进制字符串
     */
    public String getCanIdHexString() {
        return String.format("0x%08X", canId);
    }
    
    /**
     * 转换为标准CAN帧
     * J1939帧本质上是29位扩展CAN帧
     */
    public CanFrame toCanFrame() {
        CanFrame canFrame = new CanFrame(this.canId, this.data, true); // J1939使用扩展帧
        canFrame.setTimestamp(this.timestamp);
        canFrame.setDataLength(this.dataLength);
        return canFrame;
    }
    
    @Override
    public String toString() {
        return String.format("J1939Frame{CAN_ID=%s, PGN=%s, SA=0x%02X, Data=[%s], Length=%d, Priority=%d, Format=%s}",
                getCanIdHexString(), getPgnHexString(), sourceAddress, getDataHexString(), 
                dataLength, priority, isPdu1Format() ? "PDU1" : "PDU2");
    }
}